package com.kool.kmqtt.server;

import com.kool.kmqtt.server.exception.AppException;
import com.kool.kmqtt.server.exception.ErrorCode;
import com.kool.kmqtt.util.PropertyUtil;
import lombok.Getter;

import java.util.Optional;

public class ServerConfig {
    /**
     * 系统配置
     */
    private static volatile ServerConfig serverConfig = new ServerConfig();
    /**
     * 端口
     */
    @Getter
    private int port;
    private static final String PROP_PORT = "port";
    /**
     * 连接超时时间（网络连接建立开始，未收到CONNECT报文导致中断连接的时间），单位：毫秒
     */
    @Getter
    private long connectTimeout;
    private static final String PROP_CONNECT_TIMEOUT = "connect_timeout";

    /**
     * 心跳监测轮询时间间隔，单位：毫秒
     */
    @Getter
    private long keepAliveInterval;
    private static final String PROP_KEEP_ALIVE_INTERVAL = "keep_alive_interval";

    /**
     * 报文id资源池容量
     */
    @Getter
    private int packetIdPoolSize;
    private static final String PROP_PACKET_ID_POOL_SIZE = "packet_id_pool_size";

    /**
     * 仓库类型
     *
     * @see com.kool.kmqtt.server.constant.RepositoryTypeEnum
     */
    @Getter
    private String repositoryType;
    private static final String PROP_REPOSITORY_TYPE = "repository_type";

    /**
     * server发送PUBLISH的qos等级,默认2
     */
    @Getter
    private int qos;
    private static final String PROP_QOS = "server_qos";

    /**
     * ETCD地址
     */
    @Getter
    private String etcdAddress;
    private static final String PROP_ETCD_ADDRESS = "etcd_address";

    /**
     * 是否开启用户权限验证
     */
    @Getter
    private Boolean userAuthSwitch;
    private static final String PROP_USER_AUTH_SWITCH = "user_auth_switch";

    /**
     * 是否开启主题权限验证
     */
    @Getter
    private Boolean topicAuthSwitch;
    private static final String PROP_TOPIC_AUTH_SWITCH = "topic_auth_switch";

    /**
     * 是否开启熔断
     */
    @Getter
    private Boolean failoverSwitch;
    private static final String PROP_FAILOVER_SWITCH = "failover_switch";

    /**
     * 错误次数计数器重置周期，单位秒
     */
    @Getter
    private int failoverCounterResetSeconds;
    private static final String PROP_FAILOVER_COUNTER_RESET_SECONDS = "failover_counter_reset_seconds";

    /**
     * 熔断触发阈值，连接错误次数
     */
    @Getter
    private int failoverThreshold;
    private static final String PROP_FAILOVER_THRESHOLD = "failover_threshold";

    /**
     * 是否开启日志统计分析
     */
    @Getter
    private Boolean logAnalysisSwitch;
    private static final String PROP_LOG_ANALYSIS_SWITCH = "log_analysis_switch";

    private ServerConfig() {
        port = Integer.parseInt(Optional.ofNullable(PropertyUtil.getProp(PROP_PORT))
                .orElse("9000"));
        connectTimeout = Long.parseLong(Optional.ofNullable(PropertyUtil.getProp(PROP_CONNECT_TIMEOUT))
                .orElse("5000"));
        keepAliveInterval = Long.parseLong(Optional.ofNullable(PropertyUtil.getProp(PROP_KEEP_ALIVE_INTERVAL))
                .orElse("60000"));
        packetIdPoolSize = Integer.parseInt(Optional.ofNullable(PropertyUtil.getProp(PROP_PACKET_ID_POOL_SIZE))
                .orElse("50000"));
        if (packetIdPoolSize > 50000 || packetIdPoolSize < 1) {
            throw new AppException(ErrorCode.CHARSET_NOT_UTF8);
        }
        repositoryType = Optional.ofNullable(PropertyUtil.getProp(PROP_REPOSITORY_TYPE))
                .orElse("default");
        qos = Integer.parseInt(Optional.ofNullable(PropertyUtil.getProp(PROP_QOS))
                .orElse("2"));
        etcdAddress = Optional.ofNullable(PropertyUtil.getProp(PROP_ETCD_ADDRESS))
                .orElse("localhost:2379");
        userAuthSwitch = Boolean.parseBoolean(Optional.ofNullable(PropertyUtil.getProp(PROP_USER_AUTH_SWITCH))
                .orElse("false"));
        topicAuthSwitch = Boolean.parseBoolean(Optional.ofNullable(PropertyUtil.getProp(PROP_TOPIC_AUTH_SWITCH))
                .orElse("false"));
        failoverSwitch = Boolean.parseBoolean(Optional.ofNullable(PropertyUtil.getProp(PROP_FAILOVER_SWITCH))
                .orElse("false"));
        failoverCounterResetSeconds = Integer.parseInt(Optional.ofNullable(PropertyUtil.getProp(PROP_FAILOVER_COUNTER_RESET_SECONDS))
                .orElse("60"));
        failoverThreshold = Integer.parseInt(Optional.ofNullable(PropertyUtil.getProp(PROP_FAILOVER_THRESHOLD))
                .orElse("5"));
        logAnalysisSwitch = Boolean.parseBoolean(Optional.ofNullable(PropertyUtil.getProp(PROP_LOG_ANALYSIS_SWITCH))
                .orElse("false"));
    }

    public static ServerConfig getInstance() {
        return serverConfig;
    }
}
